/**
 * Test suite for service utility functions
 *
 * This module provides utilities for working with different flow types in the application.
 * Flow types determine the API endpoint prefix used for various operations.
 *
 * Key concepts:
 * - FlowType.appFlow: Standard application workflows (prefix: 'apps')
 * - FlowType.ragPipeline: RAG (Retrieval-Augmented Generation) pipelines (prefix: 'rag/pipelines')
 *
 * The getFlowPrefix function maps flow types to their corresponding API path prefixes,
 * with a fallback to 'apps' for undefined or unknown flow types.
 */
import { flowPrefixMap, getFlowPrefix } from './utils'
import { FlowType } from '@/types/common'

describe('Service Utils', () => {
  describe('flowPrefixMap', () => {
    /**
     * Test that the flowPrefixMap object contains the expected mappings
     * This ensures the mapping configuration is correct
     */
    it('should have correct flow type to prefix mappings', () => {
      expect(flowPrefixMap[FlowType.appFlow]).toBe('apps')
      expect(flowPrefixMap[FlowType.ragPipeline]).toBe('rag/pipelines')
    })

    /**
     * Test that the map only contains the expected flow types
     * This helps catch unintended additions to the mapping
     */
    it('should contain exactly two flow type mappings', () => {
      const keys = Object.keys(flowPrefixMap)
      expect(keys).toHaveLength(2)
    })
  })

  describe('getFlowPrefix', () => {
    /**
     * Test that appFlow type returns the correct prefix
     * This is the most common flow type for standard application workflows
     */
    it('should return "apps" for appFlow type', () => {
      const result = getFlowPrefix(FlowType.appFlow)
      expect(result).toBe('apps')
    })

    /**
     * Test that ragPipeline type returns the correct prefix
     * RAG pipelines have a different API structure with nested paths
     */
    it('should return "rag/pipelines" for ragPipeline type', () => {
      const result = getFlowPrefix(FlowType.ragPipeline)
      expect(result).toBe('rag/pipelines')
    })

    /**
     * Test fallback behavior when no flow type is provided
     * Should default to 'apps' prefix for backward compatibility
     */
    it('should return "apps" when flow type is undefined', () => {
      const result = getFlowPrefix(undefined)
      expect(result).toBe('apps')
    })

    /**
     * Test fallback behavior for unknown flow types
     * Any unrecognized flow type should default to 'apps'
     */
    it('should return "apps" for unknown flow type', () => {
      // Cast to FlowType to test the fallback behavior
      const unknownType = 'unknown' as FlowType
      const result = getFlowPrefix(unknownType)
      expect(result).toBe('apps')
    })

    /**
     * Test that the function handles null gracefully
     * Null should be treated the same as undefined
     */
    it('should return "apps" when flow type is null', () => {
      const result = getFlowPrefix(null as any)
      expect(result).toBe('apps')
    })

    /**
     * Test consistency with flowPrefixMap
     * The function should return the same values as direct map access
     */
    it('should return values consistent with flowPrefixMap', () => {
      expect(getFlowPrefix(FlowType.appFlow)).toBe(flowPrefixMap[FlowType.appFlow])
      expect(getFlowPrefix(FlowType.ragPipeline)).toBe(flowPrefixMap[FlowType.ragPipeline])
    })
  })

  describe('Integration scenarios', () => {
    /**
     * Test typical usage pattern in API path construction
     * This demonstrates how the function is used in real application code
     */
    it('should construct correct API paths for different flow types', () => {
      const appId = '123'

      // App flow path construction
      const appFlowPath = `/${getFlowPrefix(FlowType.appFlow)}/${appId}`
      expect(appFlowPath).toBe('/apps/123')

      // RAG pipeline path construction
      const ragPipelinePath = `/${getFlowPrefix(FlowType.ragPipeline)}/${appId}`
      expect(ragPipelinePath).toBe('/rag/pipelines/123')
    })

    /**
     * Test that the function can be used in conditional logic
     * Common pattern for determining which API endpoint to use
     */
    it('should support conditional API routing logic', () => {
      const determineEndpoint = (flowType?: FlowType, resourceId?: string) => {
        const prefix = getFlowPrefix(flowType)
        return `/${prefix}/${resourceId || 'default'}`
      }

      expect(determineEndpoint(FlowType.appFlow, 'app-1')).toBe('/apps/app-1')
      expect(determineEndpoint(FlowType.ragPipeline, 'pipeline-1')).toBe('/rag/pipelines/pipeline-1')
      expect(determineEndpoint(undefined, 'fallback')).toBe('/apps/fallback')
    })

    /**
     * Test behavior with empty string flow type
     * Empty strings should fall back to default
     */
    it('should handle empty string as flow type', () => {
      const result = getFlowPrefix('' as any)
      expect(result).toBe('apps')
    })
  })

  describe('Type safety', () => {
    /**
     * Test that all FlowType enum values are handled
     * This ensures we don't miss any flow types in the mapping
     */
    it('should handle all FlowType enum values', () => {
      // Get all enum values
      const flowTypes = Object.values(FlowType)

      // Each flow type should return a valid prefix
      flowTypes.forEach((flowType) => {
        const prefix = getFlowPrefix(flowType)
        expect(prefix).toBeTruthy()
        expect(typeof prefix).toBe('string')
        expect(prefix.length).toBeGreaterThan(0)
      })
    })

    /**
     * Test that returned prefixes are valid path segments
     * Prefixes should not contain leading/trailing slashes or invalid characters
     */
    it('should return valid path segments without leading/trailing slashes', () => {
      const appFlowPrefix = getFlowPrefix(FlowType.appFlow)
      const ragPipelinePrefix = getFlowPrefix(FlowType.ragPipeline)

      expect(appFlowPrefix).not.toMatch(/^\//)
      expect(appFlowPrefix).not.toMatch(/\/$/)
      expect(ragPipelinePrefix).not.toMatch(/^\//)
      expect(ragPipelinePrefix).not.toMatch(/\/$/)
    })
  })
})
